/* eslint-disable @typescript-eslint/no-unused-vars */
import "./index.less";
import type { InputRef } from "antd";
import { Form, Input, InputNumber, Select, Table } from "antd";
import type { FormInstance } from "antd/es/form";
import React, { useContext, useEffect, useRef, useState } from "react";
import ApiSelect from "@/components/Form/components/ApiSelect";
import { cloneDeep } from "lodash-es";
const EditableContext = React.createContext<FormInstance<any> | null>(null);
interface Item {
	key: string;
	name: string;
	age: string;
	address: string;
}

interface EditableRowProps {
	index: number;
}

const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }: any) => {
	const [form] = Form.useForm();
	return (
		<Form form={form} component={false}>
			<EditableContext.Provider value={form}>
				<tr {...props} />
			</EditableContext.Provider>
		</Form>
	);
};

interface EditableCellProps {
	title: React.ReactNode;
	editable: boolean;
	children: React.ReactNode;
	dataIndex: keyof Item;
	record: Item;
	type: String;
	componentProps: any;
	apiSelectLabel: any;
	rowRef: any;
	handleSave: (record: Item, componentProps: any) => void;
}
const formItemType = (type: any, inputRef: any, save: any, componentProps: any, onChange: any) => {
	switch (type) {
		case "Input":
			return <Input ref={inputRef} onPressEnter={save} onBlur={save} />;
		case "Select":
			return <Select ref={inputRef} onPressEnter={save} onBlur={save} options={componentProps.options} />;
		case "InputNumber":
			return <InputNumber ref={inputRef} onPressEnter={save} onBlur={save} />;
		case "ApiSelect":
			return (
				<ApiSelect
					ApiSelectRef={inputRef}
					ApiSelectPressEnter={save}
					ApiSelectBlur={save}
					api={componentProps.api}
					labelField={componentProps.labelField}
					valueField={componentProps.valueField}
					params={componentProps.params}
					onChange={onChange}
				/>
			);
		default:
			return <Input ref={inputRef} onPressEnter={save} onBlur={save} />;
	}
};

const EditableCell: React.FC<EditableCellProps> = ({
	title,
	editable,
	children,
	dataIndex,
	record,
	handleSave,
	type,
	rowRef,
	componentProps,
	apiSelectLabel,
	...restProps
}) => {
	const [editing, setEditing] = useState(false);
	const inputRef = useRef<InputRef>(null);
	const form = useContext(EditableContext)!;
	useEffect(() => {
		if (editing) {
			inputRef.current!.focus();
		}
	}, [editing]);

	const toggleEdit = () => {
		setEditing(!editing);
		form.setFieldsValue({ [dataIndex]: record[dataIndex] });
	};
	const onChange = async (value: any, option: any) => {
		const values = await form.validateFields();
		if (!rowRef.current) {
			rowRef.current = { ...values };
		} else {
			rowRef.current = { ...rowRef.current, ...values };
		}
		if (!option) return;
		apiSelectLabel.current = option["label"];
		componentProps.onChange && componentProps.onChange(value, option);
	};
	const save = async () => {
		try {
			const values = await form.validateFields();
			if (!rowRef.current) {
				rowRef.current = { ...values };
			} else {
				rowRef.current = { ...rowRef.current, ...values };
			}
			toggleEdit();
			handleSave({ ...record, ...values }, componentProps);
		} catch (errInfo) {
			console.log("Save failed:", errInfo);
		}
	};

	let childNode = children;

	if (editable) {
		if (editing) {
			childNode = (
				<Form.Item
					style={{ margin: 0 }}
					name={dataIndex}
					rules={[
						{
							required: true,
							message: `${title} is required.`
						}
					]}
				>
					{formItemType(type, inputRef, save, componentProps, onChange)}
				</Form.Item>
			);
		} else {
			childNode = (
				<div className="editable-cell-value-wrap" style={{ paddingRight: 24 }} onClick={toggleEdit}>
					{children}
				</div>
			);
		}
	}

	return <td {...restProps}>{childNode}</td>;
};

type EditableTableProps = Parameters<typeof Table>[0];

interface DataType {
	key: React.Key;
	name: string;
	age: string;
	address: string;
}

type ColumnTypes = Exclude<EditableTableProps["columns"], undefined>;

const BasicProTable: React.FC = (props: any) => {
	const dataSourceRef = useRef<DataType[]>();
	const [dataSource, setDataSource] = useState<DataType[]>();
	const [defaultColumns, setDefaultColumns] = useState([]);
	const dataRows = useRef<any>(null);
	const [key, setKey] = useState("");
	const [count, setCount] = useState(2);
	const apiSelectLabel = useRef<any>(null);
	const apiSelectValue = useRef<any>(null);
	const currentKey = useRef<any>(null);
	const list = useRef<any>([]);
	const rowRef = useRef<any>([]);
	const [selectionType, setSelectionType] = useState<"checkbox" | "radio">("checkbox");
	const handleDelete = (key: React.Key) => {
		if (!dataSourceRef.current) return;
		const newData = dataSourceRef.current.filter(item => item.key !== key);
		dataSourceRef.current = newData;
		setDataSource(dataSourceRef.current);
	};
	const handleAdd = (newData: any) => {
		if (!dataSourceRef.current) return;
		dataSourceRef.current = [...dataSourceRef.current, newData];
		setDataSource(dataSourceRef.current);
		setCount(count + 1);
	};

	const handleSave = async (row: any, componentProps?: any) => {
		if (componentProps && componentProps["valueField"]) {
			let fieldValue = row[componentProps["valueField"]];
			if (componentProps["dataIndex"]) {
				row[componentProps["dataIndex"]] = apiSelectLabel.current;
				apiSelectValue.current = {
					value: fieldValue,
					key: componentProps["dataIndex"]
				};
			} else {
				row[componentProps["valueField"]] = apiSelectLabel.current;
				apiSelectValue.current = {
					value: fieldValue,
					key: componentProps["valueField"]
				};
			}
		}
		let newData = [...dataSourceRef.current];
		const index = newData.findIndex(item => row.key === item.key);
		const item = newData[index];
		newData.splice(index, 1, {
			...item,
			...row
		});

		setDataSource(newData);
		dataSourceRef.current = newData;
	};
	const components = {
		body: {
			row: EditableRow,
			cell: EditableCell
		}
	};
	const handleCellClick = (record: any) => {
		currentKey.current = record.key;
	};
	const columns = defaultColumns.map((col: any) => {
		if (!col.editable) {
			return col;
		}
		return {
			...col,
			onCell: (record: DataType) => ({
				record,
				editable: col.editable,
				dataIndex: col.dataIndex,
				title: col.title,
				type: col.type,
				apiSelectLabel,
				rowRef,
				componentProps: col.componentProps,
				handleSave,
				onClick: () => {
					handleCellClick(record);
				}
			})
		};
	});
	const submit = () => {
		return new Promise((resolve, reject) => {
			if (selectionType) {
				resolve(dataRows.current);
				return;
			}
			if (!dataSourceRef.current) return;
			let arr = cloneDeep(dataSourceRef.current);
			arr.forEach((item: any) => {
				list.current.forEach((value: any) => {
					if (item.key === value.id) {
						item[value["key"]] = value["value"];
					}
				});
			});
			resolve(arr);
		});
	};
	const setProps = async (value: any) => {
		setKey(value.key);
		setSelectionType(value.type);
		if (value.api) {
			const res = await value.api(value.parameter);
			res.list.forEach((item: any) => {
				// for (let key in value.returnValue) {
				// 	rowRef.current = {
				// 		...rowRef.current,
				// 		[key]: item[key]
				// 	};
				// }
				for (let key in value.default) {
					item[key] = value.default[key];
				}
			});
			setDataSource(res.list);
			dataSourceRef.current = res.list;
			setDefaultColumns(value.defaultColumns);
			return;
		}
		setDataSource(value.dataSource);
		dataSourceRef.current = value.dataSource;
		setDefaultColumns(value.defaultColumns);
	};
	const setFieldsValue = (value: any) => {
		setDataSource(value);
		dataSourceRef.current = value;
	};
	const setRowData = (parameter: any) => {
		dataSourceRef.current = dataSourceRef.current?.map((item: any) => {
			if (item.key == currentKey.current) {
				item = { ...item, ...parameter };
			}
			return item;
		});
		setDataSource(dataSourceRef.current);
	};
	const getRowData = () => {
		if (!dataSourceRef.current) return;
		return rowRef.current;
	};

	const tableAction = {
		handleDelete,
		handleAdd,
		submit,
		setProps,
		setFieldsValue,
		setRowData,
		getRowData
	};
	const rowSelection = {
		onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
			dataRows.current = selectedRows;
		},
		getCheckboxProps: (record: DataType) => ({
			disabled: record.name === "Disabled User", // Column configuration not to be checked
			name: record.name
		})
	};
	useEffect(() => {
		if (!apiSelectValue.current) return;
		list.current = [
			...list.current,
			{
				...apiSelectValue.current,
				id: currentKey.current
			}
		];
	}, [apiSelectValue.current]);
	useEffect(() => {
		props.register(tableAction);
	}, []);
	useEffect(() => {
		dataSourceRef.current = dataSource;
	}, [dataSource]);
	return (
		<div className="proTable">
			<Table
				rowSelection={{
					type: selectionType,
					...rowSelection
				}}
				pagination={dataSource?.data?.total}
				components={components}
				rowClassName={() => "editable-row"}
				dataSource={dataSource}
				columns={columns as ColumnTypes}
				rowKey={key ? key : "key"}
				scroll={{ x: "max-content" }}
			/>
		</div>
	);
};

export default BasicProTable;
